/*
 * LogEx a Java library for extracting log file data
 * Copyright 2012 LogEx Team.
 *
 * This program is free software. You can distribute or modify it under the 
 * terms of the GNU Lesser General Public License version 3.0 as published by  
 * the Free Software Foundation.
 *
 * This program is distributed AS IS and WITHOUT WARRANTY. OF ANY KIND,
 * INCLUDING MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, contact the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
package org.logex.main;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.xml.xquery.XQException;
import org.ikayzo.sdl.SDL;
import org.ikayzo.sdl.SDLParseException;
import org.ikayzo.sdl.Tag;

/**
 * Performs reading lines from ASCII based log files. Uses the corresponding SDL
 * script to generate an equivalent <code>RootObject</code> object.
 * 
 * @author Lohitha Chiranjeewa
 */
public class LocalLogReader {

	private AsciiParser asciiParser;
	private String sdlFile;
	private String logFileName;
	private String logFilePath;
	private String streamLine;
	private InputStream in;
	private BufferedReader br;
	private InputStream frstream;
	private LineDetector lineDetector;

	/**
	 * Constructor for <code>LocalLogReader</code> class. Extracts log file name
	 * from path.
	 * 
	 * @param logFilePath
	 *            Name (with path) of the log file
	 * @param sdlFile
	 *            Name of the corresponding SDL file (no path needed, file needs
	 *            to be put into SDL folder)
	 */
	public LocalLogReader(String logFilePath, String sdlFile) {
		this.sdlFile = sdlFile;
		this.logFilePath = logFilePath;
		if (logFilePath.contains(File.separator)) {
			logFileName = logFilePath.substring(logFilePath
					.lastIndexOf(File.separator) + 1);
		} else {
			logFileName = logFilePath;
		}
		asciiParser = new AsciiParser(logFileName);
		try {
			frstream = new FileInputStream(logFilePath);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		in = new DataInputStream(frstream);
		br = new BufferedReader(new InputStreamReader(in));
		lineDetector = new LineDetector();
	}

	public static void main(String[] args) throws XQException, IOException,
			SDLParseException {
		LocalLogReader localLogReader = new LocalLogReader("access.log",
				"access.sdl");
		long t1 = System.currentTimeMillis();
		long m1 = Runtime.getRuntime().freeMemory();
		localLogReader.readScript();
		long t2 = System.currentTimeMillis();
		long m2 = Runtime.getRuntime().freeMemory();
		System.out.println("TIME: " + (t2 - t1));
		System.out.println("MEM: " + ((m1 - m2) / 1024));
	}

	/**
	 * Reads the SDL script and creates a <code>RootObject</code> using the
	 * created <code>Tag</code> object.
	 * 
	 * @throws IOException
	 *             If the file is not found
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws SDLParseException
	 *             If the SDL format is malformed
	 */
	public void readScript() throws IOException, XQException, SDLParseException {
		File ee = new File(StringConstants.SDL_FOLDER_NAME + File.separator
				+ sdlFile);
		Tag root1 = SDL.read(ee);
		asciiParser.setRootObject(new RootObject(root1));
		readLogFile();
	}

	/**
	 * Checks whether the log file is read previously before issuing read
	 * command.
	 * 
	 * @throws IOException
	 *             If the file is not found
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws NumberFormatException
	 *             Occurs when attempted to convert a string to one of the
	 *             numeric types
	 */
	private void readLogFile() throws NumberFormatException, IOException,
			XQException {
		int lineCount = lineDetector.checkFile(logFilePath);
		if (lineCount == 0) {
			convertToXml(lineCount);
		} else {
			for (int i = 0; i < lineCount; i++) {
				br.readLine();
			}
			convertToXml(lineCount);
		}
	}

	/**
	 * Starts matching log file lines with pattern tags.
	 * 
	 * @param lineCount
	 *            The number of lines that has been read until now
	 * @throws XQException
	 *             If reasons such as wrong commands, DB errors occur
	 * @throws IOException
	 *             Due to errors in writing to / reading from file
	 */
	private void convertToXml(int lineCount) throws XQException, IOException {
		int currentLine = 0;
		asciiParser.prepareLists();
		while ((streamLine = br.readLine()) != null) {
			currentLine++;
			asciiParser.actOnLine(streamLine);
		}
		asciiParser.writeRemainingLogEntries(streamLine, currentLine);
		in.close();
		lineDetector.writeToFile(lineCount + currentLine, logFilePath);
	}

}
